package com.jprocms.module.cms.service.email;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import com.jprocms.module.cms.api.dto.EmailConfig;
import com.jprocms.module.cms.controller.admin.mail.vo.EmailCodeSendReqDTO;
import com.jprocms.module.cms.controller.admin.mail.vo.EmailCodeUseReqDTO;
import com.jprocms.module.cms.enums.EmailSceneEnum;
import com.jprocms.module.cms.framework.cache.CacheService;
import com.jprocms.module.cms.service.globalconfig.GlobalConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

import static com.jpro.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.jprocms.module.cms.dal.redis.RedisKeyConstants.EMAIL_CODE;
import static com.jprocms.module.cms.dal.redis.RedisKeyConstants.EMAIL_CODE_USED;
import static com.jprocms.module.cms.enums.ErrorCodeConstants.EMAIL_CODE_NOT_CORRECT;
import static com.jprocms.module.cms.enums.ErrorCodeConstants.EMAIL_CODE_SEND_MAXIMUM_QUANTITY_PER_DAY;

/**
 * 邮箱验证码 Service 实现类
 *
 * @author JPROCMS
 */
@Service
@Validated
public class EmailCodeServiceImpl implements EmailCodeService {
    @Resource
    private EmailService emailSendService;
    @Resource
    private CacheService cacheService;
    @Resource
    private GlobalConfigService globalConfigService;


    @Override
    public void sendEmailCode(EmailCodeSendReqDTO reqDTO) {
        EmailConfig emailConfig = globalConfigService.getDefGlobalConfig().getEmailConfig();
        EmailSceneEnum sceneEnum = EmailSceneEnum.getCodeByScene(reqDTO.getScene());
        Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene());
        // 创建验证码
        String code = createEmailCode(reqDTO.getEmail(), reqDTO.getScene());
        // 发送验证码
        emailSendService.sendMail(new String[]{reqDTO.getEmail()}, emailConfig.getSubject(), StringUtils.replace(emailConfig.getText(), "${code}", code));
    }

    private String createEmailCode(String email, Integer scene) {
        EmailConfig emailConfig = globalConfigService.getDefGlobalConfig().getEmailConfig();
        final int oneDayCodeSendMax = emailConfig.getOneDayCodeSendMax();
        final Object cacheObject = cacheService.getCacheObject(EMAIL_CODE_USED + email);
        Integer emailDayUsed = 1;
        if (cacheObject != null) {
            final int emailCodeUsed = Integer.parseInt(cacheObject.toString());
            emailDayUsed = emailCodeUsed + 1;
            if (emailCodeUsed > oneDayCodeSendMax) {
                throw exception(EMAIL_CODE_SEND_MAXIMUM_QUANTITY_PER_DAY);
            }
        }
        final String code = RandomUtil.randomString(emailConfig.getVerificationCodeLength());
        cacheService.setCacheObject(EMAIL_CODE + email + ":" + scene, code, emailConfig.getVerificationCodeExpires(), TimeUnit.MINUTES);
        cacheService.setCacheObject(EMAIL_CODE_USED + email, emailDayUsed, 1L, TimeUnit.DAYS);
        return code;
    }

    @Override
    public boolean validateEmailCode(EmailCodeUseReqDTO reqDTO) {
        // 校验验证码
        String email = reqDTO.getEmail();
        final String code = reqDTO.getCode();
        final Integer scene = reqDTO.getScene();
        final Object cacheCode = cacheService.getCacheObject(EMAIL_CODE + email + ":" + scene);
        // 若验证码不存在，抛出异常
        if (cacheCode == null) {
            throw exception(EMAIL_CODE_NOT_CORRECT);
        }
        if (!cacheCode.toString().equals(code)) {
            throw exception(EMAIL_CODE_NOT_CORRECT);
        }
        //验证正确则删除
        cacheService.deleteObject(EMAIL_CODE + email + ":" + scene);
        return true;
    }


}
